/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use crate::commands::common_command::{AssociateId, ScheduleInfo, ScheduleParam, CredentialInfo};
use crate::commands::enrollment_commands::{EnrollResultInfo, EnrollParam};
use crate::common::constants::*;
use crate::common::types::*;
use crate::traits::auth_policy_manager::{AuthPolicyManagerRegistry, AuthPolicy};
use crate::traits::config_manager::ConfigManagerRegistry;
use crate::traits::crypto_engine::{CryptoEngineRegistry, KeyPair};
use crate::traits::edit_session::EditSession;
use crate::traits::edit_session_manager::EditSessionManagerRegistry;
use crate::traits::executor_manager::{ExecutorInfo, ExecutorManagerRegistry, ExecutorFilter};
use crate::traits::misc_manager::MiscManagerRegistry;
use crate::traits::time_keeper::TimeKeeperRegistry;
use crate::traits::user_db_manager::{CredentialFilter, UserDbManagerRegistry, Credential};
use crate::utils::attribute::{AttributeKey, Attribute};
use crate::utils::auth_token::AuthToken;
use crate::utils::message_codec::{MessageCodec, MessageSignParam};
use crate::{Box, log_e, Vec};

const INVALID_CAPABILITY_LEVEL: u32 = 100;
const INVALID_SENSOR_HINT: u32 = 0;

#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PermissionCheckParam {
    pub user_id: i32,
    pub auth_type: AuthType,
    pub executor_sensor_hint: u32,
    pub user_type: UserType
}

impl PermissionCheckParam {
    pub fn new(user_id: i32, auth_type: AuthType, executor_sensor_hint: u32, user_type: UserType) -> Self {
        Self {
            user_id,
            auth_type,
            executor_sensor_hint,
            user_type
        }
    }
}

#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CredentialCondition {
    condition_factor: u64,
    credential_id: u64,
    template_id: u64,
    auth_type: u32,
    executor_sensor_hint: u32,
    executor_matcher: u32,
    user_id: i32
}

pub struct FaceEnrollContext {
    schedule_info: ScheduleInfo
}

impl FaceEnrollContext {
    pub fn schedule_id(&self) -> u64 {
        self.schedule_info.schedule_id
    }

    //BEGIN_ENROLL
    pub fn begin(&mut self, enroll_param : &EnrollParam) -> Result<Vec<ScheduleInfo>, ErrorCode> {
        let check_param = PermissionCheckParam::new(
            enroll_param.user_id,
            enroll_param.auth_type,
            enroll_param.executor_sensor_hint,
            enroll_param.user_type
        );

        //检查录入权限
        self.check_enroll_permission(&check_param)?;

        //获取schedule param
        let schedule_param = self.set_schedule_param(&check_param)?;

        //获取executor_indexes
        let executor_indexes = self.get_executor_indexes(&schedule_param)?;
    
        //获取executor_messages
        let capability_level = INVALID_CAPABILITY_LEVEL;
        let executor_messages = self.get_executor_messages(&schedule_param, capability_level)?;

        //生成schedule_info
        self.generate_schedule_info(schedule_param, executor_indexes, executor_messages);
    
        let mut schedule_info_vec = crate::Vec::new();
        schedule_info_vec.push(self.schedule_info.clone());
        Ok(schedule_info_vec)
    }

    //UPDATE_ENROLL_RESULT
    pub fn update_result(&self, user_id: i32, schedule_result: &Vec<u8>) -> Result<EnrollResultInfo, ErrorCode> {
        if schedule_result.len() == 0 {
            log_e!("enroll token is invalid");
            return Err(ErrorCode::BadParam);
        }

        //获取录入结果
        let enroll_result_info = self.get_enroll_result(user_id, schedule_result)?;

        Ok(enroll_result_info)
    }

    //检查录入权限
    fn check_enroll_permission(&self, check_param : &PermissionCheckParam) -> Result<(), ErrorCode> {
        //检查authtype是否支持
        let enable_status = ConfigManagerRegistry::get().get_enable_status(check_param.auth_type, check_param.user_id)?;
        if !enable_status {
            log_e!("authtype {:?} is not support", check_param.auth_type);
        }

        //检查session是否有效
        let edit_session: &mut EditSession = EditSessionManagerRegistry::get_mut().get_edit_session()?;
        edit_session.check_valid(Some(check_param.user_id))?;
        
        //检查user_type是否有效
        self.is_valid_user_type(check_param.user_type)?;

        //检查对应user_id的对应auth_type是否支持，支持的话是否已经存满
        self.is_auth_type_available(check_param.user_id, check_param.auth_type)?;

        Ok(())
    }

    //检查user_type是否有效
    fn is_valid_user_type(&self, user_type: UserType) -> Result<(), ErrorCode> {
        if user_type != UserType::Main && user_type != UserType::Sub && user_type != UserType::Private {
            log_e!("user type {:?} is invalid", user_type);
            return Err(ErrorCode::BadParam);
        }

        Ok(())
    }

    //检查对应user_id的对应auth_type是否支持，支持的话是否已经存满
    fn is_auth_type_available(&self, user_id: i32, auth_type: AuthType) -> Result<(), ErrorCode> {
        let max_credential_number_per_user =AuthPolicyManagerRegistry::get()
            .get_auth_policy(auth_type)?
            .get_max_credential_number_per_user();
        
        //检查对应的auth_type是否支持
        if max_credential_number_per_user == 0 {
            log_e!("max number is 0, auth type {:?} not support", auth_type);
            return Err(ErrorCode::TypeNotSupport);
        }

        let filter = Box::new(move |cred: &Credential| {
            cred.user_id == user_id && cred.auth_type == auth_type});
        let credential_list = UserDbManagerRegistry::get().get_credential_list(filter)?;

        //检查是否已经存满
        if credential_list.len() >= max_credential_number_per_user {
            log_e!("the enrolled authtype: {:?} has reached the upper limit {}", auth_type, max_credential_number_per_user);
            return Err(ErrorCode::ExceedLimit);
        }
        
        Ok(())
    }

    //获取schedule param
    fn set_schedule_param(&self, check_param : &PermissionCheckParam) -> Result <ScheduleParam, ErrorCode> {
        let mut associate_id = AssociateId::init();

        //获取template_id_list
        let template_ids = self.get_template_id_list(check_param.user_id, check_param.auth_type)?;

        //获取executor_matcher
        let executor_matcher = self.get_executor_matcher(check_param.executor_sensor_hint, check_param.auth_type)?;
        associate_id.user_id = check_param.user_id;
        let local_udid = MiscManagerRegistry::get().get_udid()?;
        let collector_udid = MiscManagerRegistry::get().get_udid()?;

        //生成schedule_param
        let schedule_param = ScheduleParam::new (
            check_param.auth_type,
            ScheduleMode::Enroll,
            associate_id,
            template_ids,
            check_param.executor_sensor_hint,
            check_param.executor_sensor_hint,
            executor_matcher,
            check_param.user_type,
            local_udid,
            collector_udid
        );

        Ok(schedule_param)
    }

    //获取template_id_list
    fn get_template_id_list(&self, user_id: i32, auth_type: AuthType) -> Result<Vec<TemplateId>, ErrorCode> {
        let filter = Box::new(move |cred: &Credential| {
            cred.user_id == user_id && cred.auth_type == auth_type});

        //获取credential_list
        let credential_list = UserDbManagerRegistry::get().get_credential_list(filter)?;

        // 提取所有template_id
        let template_id_list = credential_list
            .iter()
            .map(|cred| cred.template_id)
            .collect::<Vec<TemplateId>>();

        Ok(template_id_list)
    }

    //获取executor_matcher
    fn get_executor_matcher(&self, executor_sensor_hint: u32, auth_type: AuthType) -> Result<u32, ErrorCode> {
        let filter: ExecutorFilter = Box::new(move |executor: &ExecutorInfo| {
            executor.auth_type == auth_type &&
            executor.sensor_hint == executor_sensor_hint &&
            (executor.role == ExecutorRole::Collector || 
            executor.role == ExecutorRole::AllInOne)
        });

        //获取对应的executor_info
        let executor_info = ExecutorManagerRegistry::get().get_executor(filter)?;
        Ok(executor_info.matcher)
    }

    //获取executor_indexes
    fn get_executor_indexes(&self, schedule_param: &ScheduleParam) -> Result<Vec<u64>, ErrorCode> {
        if schedule_param.collector_sensor_hint == INVALID_SENSOR_HINT &&
            schedule_param.verifier_sensor_hint == INVALID_SENSOR_HINT {
            log_e!("query executor failed");
            return Err(ErrorCode::Unknown);
        }

        if (schedule_param.collector_sensor_hint == INVALID_SENSOR_HINT ||
            schedule_param.verifier_sensor_hint == INVALID_SENSOR_HINT ||
            schedule_param.collector_sensor_hint == schedule_param.verifier_sensor_hint) &&
            (schedule_param.local_udid == schedule_param.collector_udid) {
            //all in one
            let all_in_one_sensor_hint = schedule_param.collector_sensor_hint | schedule_param.verifier_sensor_hint;
            let all_in_one_indexes = self.get_specific_executor_indexes(
                all_in_one_sensor_hint,
                schedule_param.executor_matcher,
                schedule_param.local_udid,
                ExecutorRole::AllInOne)?;
            return Ok(all_in_one_indexes);
        } else {
            //verifier
            let verifier_indexes = self.get_specific_executor_indexes(
                schedule_param.verifier_sensor_hint,
                schedule_param.executor_matcher,
                schedule_param.local_udid,
                ExecutorRole::Verifier)?;

            //collector
            let collector_indexes = self.get_specific_executor_indexes(
                schedule_param.collector_sensor_hint,
                schedule_param.executor_matcher,
                schedule_param.collector_udid,
                ExecutorRole::Collector)?;

            //verifier + collector
            let total_indexes: Vec<_> = verifier_indexes.iter()
                .chain(collector_indexes.iter())
                .copied()
                .collect();
            return Ok(total_indexes);
        }
    }

    //根据不同的入参信息获取特点的满足条件的executor_indexes
    fn get_specific_executor_indexes(&self, sensor_hint: u32, matcher: u32, udid: Udid, role: ExecutorRole) -> Result<Vec<u64>, ErrorCode> {
        let filter: ExecutorFilter = Box::new(move |executor: &ExecutorInfo| {
            executor.sensor_hint == sensor_hint &&
            executor.matcher == matcher &&
            executor.device_udid == udid && 
            executor.role == role
        });
        let executor_info_list = ExecutorManagerRegistry::get().get_executor_list(filter);
        let executor_indexes = executor_info_list
            .into_iter()
            .map(|executor| executor.executor_index)
            .collect::<Vec<u64>>();
        Ok(executor_indexes)
    }

    //获取executor_messages
    fn get_executor_messages(&self, schedule_param: &ScheduleParam, capability_level: u32) -> Result <Vec<u8>, ErrorCode> {
        let template_ids = unsafe {
            core::slice::from_raw_parts(
                schedule_param.template_ids.as_ptr() as *const u64,
                schedule_param.template_ids.len()
            )
        };

        //将executor_message存到attribute中
        let mut attribute = Attribute::new();
        attribute.set_u64_slice(AttributeKey::AttrTemplateIdList, template_ids);
        attribute.set_u32(AttributeKey::AttrCapabilityLevel, capability_level);
        attribute.set_u64(AttributeKey::AttrScheduleId, self.schedule_info.schedule_id);

        let empty_keypair = KeyPair {
            pub_key: Vec::new(),
            pri_key: Vec::new(),
        };
        let message_codec = MessageCodec::new(MessageSignParam::Executor(empty_keypair));

        //将attribute进行序列化，生成executor_messages
        let executor_messages = message_codec.serialize_attribute(&attribute)?;
        Ok(executor_messages)
    }

    //生成schedule_info
    fn generate_schedule_info(&mut self, schedule_param: ScheduleParam, executor_indexes: Vec<u64>, executor_messages: Vec<u8>) {
        self.schedule_info.template_ids = schedule_param.template_ids;
        self.schedule_info.auth_type = schedule_param.auth_type;
        self.schedule_info.executor_matcher = schedule_param.executor_matcher;
        self.schedule_info.schedule_mode = schedule_param.schedule_mode;
        self.schedule_info.executor_indexes = executor_indexes;
        self.schedule_info.executor_messages.push(executor_messages);
    }

    //获取录入结果
    fn get_enroll_result(&self, user_id: i32, schedule_result: &Vec<u8>) -> Result<EnrollResultInfo, ErrorCode> {
        let edit_session: &mut EditSession = EditSessionManagerRegistry::get_mut().get_edit_session()?;
        let session_user_id = edit_session.user_id();

        //检查user_id与当前session的user_id是否匹配
        if session_user_id != user_id {
            log_e!("user id mismatch");
            return Err(ErrorCode::Unknown);
        }

        //检查会话是否超时
        edit_session.check_valid(None)?;

        let empty_keypair = KeyPair {
            pub_key: Vec::new(),
            pri_key: Vec::new(),
        };
        let message_codec = MessageCodec::new(MessageSignParam::Executor(empty_keypair));

        //将schedule_result反序列化
        let attribute = message_codec.deserialize_attribute(schedule_result)?;

        //随机生成一个不重复的credential_id
        let credential_id = self.generate_unique_credential_id()?;

        //生成credential_info
        let credential_info = self.generate_credential_info(&attribute, credential_id)?;

        //生成auth_token
        let auth_token = self.generate_enroll_token(edit_session, user_id, credential_id)?;

        //获取root_secret
        let root_secret = self.get_root_secret(&attribute, AttributeKey::AttrRootSecret)?;
        let old_root_secret = self.get_root_secret(&attribute, AttributeKey::AttrOldRootSecret)?;

        let enroll_result_info = EnrollResultInfo {
            credential_id: credential_id,
            old_info: credential_info,
            root_secret: Some(root_secret),
            old_root_secret: Some(old_root_secret),
            auth_token: auth_token
        };

        Ok(enroll_result_info)
    }

    //获取root secret
    fn get_root_secret(&self, attribute: &Attribute, key: AttributeKey) -> Result<[u8; ROOT_SECRET_LEN], ErrorCode> {
        let root_secret_slice = attribute.get_u8_slice(key)?;
        if root_secret_slice.len() != ROOT_SECRET_LEN {
            log_e!("root secret length mismatch");
            return Err(ErrorCode::GeneralError);
        }
        let mut root_secret = [0u8; ROOT_SECRET_LEN];
        root_secret.copy_from_slice(root_secret_slice);
        Ok(root_secret)
    }

    //生成非重复的credential id
    fn generate_unique_credential_id(&self) -> Result<CredentialId, ErrorCode> {
        let mut credential_id = [0u8; 8];
        let filter = Box::new(move |_cred: &Credential| true);
        let credential_list = UserDbManagerRegistry::get().get_credential_list(filter)?.clone();
    
        CryptoEngineRegistry::get()
            .secure_random_with_check(
                &mut credential_id,
                Box::new(move |bytes: &[u8]| {
                    if bytes.len() != size_of::<u64>() {
                        return false;
                    }
                    let credential_id = u64::from_ne_bytes(bytes.try_into().unwrap());
                    !credential_list.iter().any(|e| e.credential_id == CredentialId(credential_id))
                }),
            )
            .map_err(|_| ErrorCode::GeneralError)?;

        Ok(CredentialId(u64::from_ne_bytes(credential_id)))
    }

    //生成credential_info
    fn generate_credential_info(&self, attribute: &Attribute, credential_id: CredentialId) -> Result<CredentialInfo, ErrorCode> {
        let executor_index = self.schedule_info.executor_indexes.first().unwrap().clone();
        let template_id = TemplateId(attribute.get_u64(AttributeKey::AttrTemplateId)?);
        let auth_type = self.schedule_info.auth_type;
        let executor_matcher = self.schedule_info.executor_matcher;
        let filter: ExecutorFilter = Box::new(move |executor: &ExecutorInfo| {
            executor.executor_index == executor_index
        });
        let executor_sensor_hint = ExecutorManagerRegistry::get().get_executor(filter)?.sensor_hint;
        let auth_sub_type = attribute.get_i32(AttributeKey::AttrPinSubType)?;
        let is_abandoned = false;
        let validity_period = UserDbManagerRegistry::get().get_credential_valid_peroid(credential_id)?;

        let credential_info = CredentialInfo {
            credential_id: credential_id,
            executor_index: executor_index,
            template_id: template_id,
            auth_type: auth_type,
            executor_matcher: executor_matcher,
            executor_sensor_hint: executor_sensor_hint,
            auth_sub_type: auth_sub_type,
            is_abandoned: is_abandoned,
            validity_period: validity_period,
        };

        Ok(credential_info)
    }

    //生成auth_token
    fn generate_enroll_token(&self, edit_session: &mut EditSession, user_id: i32, credential_id: CredentialId) -> Result<Vec<u8>, ErrorCode> {
        //明文
        let challenge = edit_session.challenge().clone();
        let time = TimeKeeperRegistry::get().get_system_time()?;
        let auth_trust_level = AuthTrustLevel::Atl3;
        let auth_type = self.schedule_info.auth_type;
        let schedule_mode = ScheduleMode::Enroll;
        let security_level = AuthSecurityLevel::Asl0;
        let token_type = TokenType::LocalAuth;

        //密文
        let secure_uid = UserDbManagerRegistry::get().get_user(user_id)?.sec_uid;
        let enrolled_id = UserDbManagerRegistry::get().get_enrolled_id(user_id, auth_type)?;
        let collector_udid = MiscManagerRegistry::get().get_udid()?;
        let verifier_udid = MiscManagerRegistry::get().get_udid()?;

        let mut origin_auth_token = AuthToken::new(
            challenge,
            time,
            auth_trust_level,
            auth_type,
            schedule_mode,
            security_level,
            token_type,
            user_id,
            secure_uid,
            enrolled_id,
            credential_id,
            collector_udid,
            verifier_udid
        );

        let auth_token = origin_auth_token.encode_to_slice()?;

        Ok(auth_token)
    }
}